from typing import List, Optional, Dict, Any
from sqlalchemy.orm import Session
from sqlalchemy import and_, or_, func
from datetime import datetime, timedelta
from uuid import UUID

from app.models.maintenance_record import MaintenanceRecord, MaintenanceStatus, MaintenanceType
from app.schemas.maintenance_record import (
    MaintenanceRecordCreate, 
    MaintenanceRecordUpdate, 
    MaintenanceRecordComplete,
    MaintenanceRecordFilter,
    MaintenanceStatsResponse
)

class MaintenanceRecordService:
    """维护记录服务类"""
    
    def get(self, db: Session, record_id: UUID) -> Optional[MaintenanceRecord]:
        """获取单个维护记录"""
        return db.query(MaintenanceRecord).filter(MaintenanceRecord.id == record_id).first()
    
    def get_multi(
        self, 
        db: Session, 
        *, 
        skip: int = 0, 
        limit: int = 100,
        filters: Optional[MaintenanceRecordFilter] = None
    ) -> List[MaintenanceRecord]:
        """获取维护记录列表"""
        query = db.query(MaintenanceRecord)
        
        if filters:
            if filters.device_id:
                query = query.filter(MaintenanceRecord.device_id == filters.device_id)
            if filters.maintenance_type:
                query = query.filter(MaintenanceRecord.maintenance_type == filters.maintenance_type)
            if filters.status:
                query = query.filter(MaintenanceRecord.status == filters.status)
            if filters.priority:
                query = query.filter(MaintenanceRecord.priority == filters.priority)
            if filters.assigned_to:
                query = query.filter(MaintenanceRecord.assigned_to == filters.assigned_to)
            if filters.performed_by:
                query = query.filter(MaintenanceRecord.performed_by == filters.performed_by)
            if filters.start_date:
                query = query.filter(MaintenanceRecord.scheduled_at >= filters.start_date)
            if filters.end_date:
                query = query.filter(MaintenanceRecord.scheduled_at <= filters.end_date)
            if filters.is_overdue is not None:
                if filters.is_overdue:
                    query = query.filter(
                        and_(
                            MaintenanceRecord.scheduled_at < datetime.now(),
                            MaintenanceRecord.status.in_([MaintenanceStatus.SCHEDULED, MaintenanceStatus.IN_PROGRESS])
                        )
                    )
                else:
                    query = query.filter(
                        or_(
                            MaintenanceRecord.scheduled_at >= datetime.now(),
                            MaintenanceRecord.status.in_([MaintenanceStatus.COMPLETED, MaintenanceStatus.CANCELLED])
                        )
                    )
        
        return query.order_by(MaintenanceRecord.scheduled_at.desc()).offset(skip).limit(limit).all()
    
    def create(self, db: Session, *, obj_in: MaintenanceRecordCreate, created_by: UUID) -> MaintenanceRecord:
        """创建维护记录"""
        obj_data = obj_in.model_dump()
        obj_data["created_by"] = created_by
        
        db_obj = MaintenanceRecord(**obj_data)
        db.add(db_obj)
        db.commit()
        db.refresh(db_obj)
        return db_obj
    
    def update(self, db: Session, *, db_obj: MaintenanceRecord, obj_in: MaintenanceRecordUpdate) -> MaintenanceRecord:
        """更新维护记录"""
        obj_data = obj_in.model_dump(exclude_unset=True)
        
        for field, value in obj_data.items():
            if hasattr(db_obj, field):
                setattr(db_obj, field, value)
        
        db.add(db_obj)
        db.commit()
        db.refresh(db_obj)
        return db_obj
    
    def start_maintenance(self, db: Session, *, record_id: UUID, performed_by: UUID) -> Optional[MaintenanceRecord]:
        """开始维护工作"""
        db_obj = self.get(db, record_id)
        if not db_obj:
            return None
        
        if db_obj.status != MaintenanceStatus.SCHEDULED:  # type: ignore
            raise ValueError("只能开始已安排的维护工作")
        
        db_obj.status = MaintenanceStatus.IN_PROGRESS  # type: ignore
        db_obj.started_at = datetime.now()  # type: ignore
        db_obj.performed_by = performed_by  # type: ignore
        
        db.add(db_obj)
        db.commit()
        db.refresh(db_obj)
        return db_obj
    
    def complete_maintenance(
        self, 
        db: Session, 
        *, 
        record_id: UUID, 
        completion_data: MaintenanceRecordComplete
    ) -> Optional[MaintenanceRecord]:
        """完成维护工作"""
        db_obj = self.get(db, record_id)
        if not db_obj:
            return None
        
        if db_obj.status != MaintenanceStatus.IN_PROGRESS:  # type: ignore
            raise ValueError("只能完成正在进行中的维护工作")
        
        # 更新完成信息
        completion_dict = completion_data.model_dump()
        for field, value in completion_dict.items():
            if hasattr(db_obj, field):
                setattr(db_obj, field, value)
        
        db_obj.status = MaintenanceStatus.COMPLETED  # type: ignore
        
        # 计算实际持续时间
        if db_obj.started_at and not db_obj.actual_duration:  # type: ignore
            duration = (completion_data.completed_at - db_obj.started_at).total_seconds() / 60  # type: ignore
            db_obj.actual_duration = int(duration)  # type: ignore
        
        db.add(db_obj)
        db.commit()
        db.refresh(db_obj)
        return db_obj
    
    def approve_maintenance(
        self, 
        db: Session, 
        *, 
        record_id: UUID, 
        approved_by: UUID,
        approved: bool
    ) -> Optional[MaintenanceRecord]:
        """审核维护记录"""
        db_obj = self.get(db, record_id)
        if not db_obj:
            return None
        
        if db_obj.status != MaintenanceStatus.COMPLETED:  # type: ignore
            raise ValueError("只能审核已完成的维护记录")
        
        db_obj.approved_by = approved_by  # type: ignore
        db_obj.approved_at = datetime.now()  # type: ignore
        
        if not approved:
            db_obj.status = MaintenanceStatus.IN_PROGRESS  # 退回重做  # type: ignore
        
        db.add(db_obj)
        db.commit()
        db.refresh(db_obj)
        return db_obj
    
    def cancel_maintenance(self, db: Session, *, record_id: UUID) -> Optional[MaintenanceRecord]:
        """取消维护记录"""
        db_obj = self.get(db, record_id)
        if not db_obj:
            return None
        
        if db_obj.status in [MaintenanceStatus.COMPLETED, MaintenanceStatus.CANCELLED]:
            raise ValueError("不能取消已完成或已取消的维护记录")
        
        db_obj.status = MaintenanceStatus.CANCELLED  # type: ignore
        
        db.add(db_obj)
        db.commit()
        db.refresh(db_obj)
        return db_obj
    
    def get_overdue_records(self, db: Session) -> List[MaintenanceRecord]:
        """获取逾期的维护记录"""
        return db.query(MaintenanceRecord).filter(
            and_(
                MaintenanceRecord.scheduled_at < datetime.now(),
                MaintenanceRecord.status.in_([MaintenanceStatus.SCHEDULED, MaintenanceStatus.IN_PROGRESS])
            )
        ).all()
    
    def update_overdue_status(self, db: Session) -> int:
        """更新逾期记录状态"""
        overdue_records = self.get_overdue_records(db)
        count = 0
        
        for record in overdue_records:
            if record.status == MaintenanceStatus.SCHEDULED:  # type: ignore
                record.status = MaintenanceStatus.OVERDUE  # type: ignore
                db.add(record)
                count += 1
        
        if count > 0:
            db.commit()
        
        return count
    
    def get_stats(
        self, 
        db: Session, 
        *, 
        device_id: Optional[UUID] = None,
        start_date: Optional[datetime] = None,
        end_date: Optional[datetime] = None
    ) -> MaintenanceStatsResponse:
        """获取维护统计信息"""
        query = db.query(MaintenanceRecord)
        
        if device_id:
            query = query.filter(MaintenanceRecord.device_id == device_id)
        if start_date:
            query = query.filter(MaintenanceRecord.scheduled_at >= start_date)
        if end_date:
            query = query.filter(MaintenanceRecord.scheduled_at <= end_date)
        
        all_records = query.all()
        total_records = len(all_records)
        
        if total_records == 0:
            return MaintenanceStatsResponse(
                total_records=0,
                completed_records=0,
                pending_records=0,
                overdue_records=0,
                completion_rate=0.0,
                total_cost=0
            )
        
        completed_records = len([r for r in all_records if r.status == MaintenanceStatus.COMPLETED])  # type: ignore
        pending_records = len([r for r in all_records if r.status in [MaintenanceStatus.SCHEDULED, MaintenanceStatus.IN_PROGRESS]])  # type: ignore
        overdue_records = len([r for r in all_records if r.status == MaintenanceStatus.OVERDUE])  # type: ignore
        
        completion_rate = completed_records / total_records if total_records > 0 else 0.0
        
        # 计算平均持续时间
        completed_with_duration = [r for r in all_records if r.status == MaintenanceStatus.COMPLETED and r.actual_duration]  # type: ignore
        average_duration = None
        if completed_with_duration:
            total_duration = sum(r.actual_duration for r in completed_with_duration)  # type: ignore
            average_duration = total_duration / len(completed_with_duration)
        
        # 计算总成本
        total_cost = sum(r.cost or 0 for r in all_records)  # type: ignore
        
        return MaintenanceStatsResponse(
            total_records=total_records,
            completed_records=completed_records,
            pending_records=pending_records,
            overdue_records=overdue_records,
            completion_rate=completion_rate,
            average_duration=float(average_duration) if average_duration else None,  # type: ignore
            total_cost=int(total_cost)  # type: ignore
        )
    
    def remove(self, db: Session, *, id: UUID) -> Optional[MaintenanceRecord]:
        """删除维护记录"""
        obj = db.query(MaintenanceRecord).get(id)
        if obj:
            db.delete(obj)
            db.commit()
        return obj